//! 系统日志 Appender 模块
//!
//! 提供跨平台系统日志集成，FATAL 级别日志自动写入系统日志。
//!
//! ## 平台支持
//!
//! - Windows: Event Log
//! - Linux: systemd journal
//! - macOS: os_log
//!
//! ## 核心特性
//!
//! - FATAL 级别日志自动同步写入系统日志
//! - 系统日志写入失败时优雅降级到 stderr
//! - 使用条件编译隔离平台特定代码
//!
//! ## 示例
//!
//! ```rust,ignore
//! use log4r::appender::syslog::{get_syslog_appender, SyslogAppender};
//! use log4r::{LogEvent, Level};
//!
//! // 获取当前平台的系统日志 Appender
//! if let Some(appender) = get_syslog_appender("my_app") {
//!     let event = LogEvent::new(Level::Fatal, "my_app", "严重错误");
//!     appender.write_syslog(&event).ok();
//! }
//! ```

#[cfg(target_os = "windows")]
pub mod windows;

#[cfg(target_os = "linux")]
pub mod linux;

#[cfg(target_os = "macos")]
pub mod macos;

// Mock 模块：测试环境或 mock-syslog feature 启用时可用
#[cfg(any(test, feature = "mock-syslog"))]
pub mod mock;

use std::sync::atomic::{AtomicU64, Ordering};

use crate::error::Log4rError;
use crate::event::LogEvent;

// ============================================================================
// 降级警告限流器
// ============================================================================

/// 降级警告限流器
///
/// 避免系统日志持续失败时警告刷屏。
/// 使用 `AtomicU64` 实现线程安全的计数。
///
/// ## 限流策略
///
/// - 第 1 次降级：输出警告
/// - 第 2-1000 次降级：静默（仅输出原始日志）
/// - 第 1001 次降级：输出警告
/// - 以此类推...
struct FallbackRateLimiter {
    /// 降级计数器
    count: AtomicU64,
    /// 警告间隔（每 N 次输出一次警告）
    interval: u64,
}

impl FallbackRateLimiter {
    /// 创建新的限流器
    ///
    /// # Arguments
    ///
    /// * `interval` - 警告间隔，每 N 次输出一次警告
    const fn new(interval: u64) -> Self {
        Self {
            count: AtomicU64::new(0),
            interval,
        }
    }

    /// 增加计数并判断是否应该输出警告
    ///
    /// 第 1 次、第 1001 次、第 2001 次... 返回 true
    ///
    /// # Returns
    ///
    /// * `true` - 应该输出警告
    /// * `false` - 静默处理
    fn should_log_warning(&self) -> bool {
        let count = self.count.fetch_add(1, Ordering::Relaxed);
        count % self.interval == 0
    }

    /// 获取当前降级次数
    ///
    /// # Returns
    ///
    /// 返回自程序启动以来的降级总次数
    fn get_count(&self) -> u64 {
        self.count.load(Ordering::Relaxed)
    }

    /// 重置计数器（用于测试）
    #[cfg(test)]
    fn reset(&self) {
        self.count.store(0, Ordering::Relaxed);
    }
}

/// 全局降级限流器，每 1000 次输出一次警告
static FALLBACK_RATE_LIMITER: FallbackRateLimiter = FallbackRateLimiter::new(1000);

/// 系统日志 Appender 接口
///
/// 所有平台实现必须满足此 trait。
/// FATAL 级别日志通过此接口同步写入系统日志。
///
/// ## 线程安全
///
/// 实现必须是 `Send + Sync`，以支持多线程环境。
///
/// ## 实现者注意事项
///
/// - `write_syslog` 必须是同步操作，确保进程崩溃前完成写入
/// - 错误应通过 `Result` 返回，禁止使用 panic/unwrap/expect
/// - 实现应处理 UTF-8 到平台原生编码的转换
///
/// ## 示例
///
/// ```rust,ignore
/// use log4r::appender::syslog::SyslogAppender;
/// use log4r::{LogEvent, Log4rError};
///
/// struct MySyslogAppender {
///     source_name: String,
/// }
///
/// impl SyslogAppender for MySyslogAppender {
///     fn write_syslog(&self, event: &LogEvent) -> Result<(), Log4rError> {
///         // 实现系统日志写入
///         Ok(())
///     }
///
///     fn name(&self) -> &'static str {
///         "MySyslogAppender"
///     }
/// }
/// ```
pub trait SyslogAppender: Send + Sync {
    /// 同步写入系统日志
    ///
    /// # Arguments
    ///
    /// * `event` - 要写入的日志事件
    ///
    /// # Returns
    ///
    /// * `Ok(())` - 写入成功
    /// * `Err(Log4rError)` - 写入失败（触发降级）
    ///
    /// # Errors
    ///
    /// * `Log4rError::AppenderError` - 系统日志写入失败
    fn write_syslog(&self, event: &LogEvent) -> Result<(), Log4rError>;

    /// 获取 Appender 名称（用于错误报告）
    ///
    /// # Returns
    ///
    /// 返回 Appender 的静态名称字符串
    fn name(&self) -> &'static str;
}

/// 获取当前平台的系统日志 Appender
///
/// 根据编译目标平台返回对应的系统日志 Appender 实现。
/// 在不支持的平台上返回 `None`。
///
/// # Arguments
///
/// * `app_name` - 应用名称，用于系统日志标识
///
/// # Returns
///
/// * `Some(Box<dyn SyslogAppender>)` - 当前平台支持系统日志
/// * `None` - 当前平台不支持系统日志
///
/// # 平台支持
///
/// | 平台 | 实现 | 事件源/标识符 |
/// |------|------|--------------|
/// | Windows | WindowsEventLog | app_name → Event Source |
/// | Linux | JournaldAppender | app_name → SYSLOG_IDENTIFIER |
/// | macOS | OsLogAppender | app_name → Subsystem |
///
/// # 示例
///
/// ```rust,ignore
/// use log4r::appender::syslog::get_syslog_appender;
///
/// if let Some(appender) = get_syslog_appender("my_app") {
///     println!("系统日志 Appender: {}", appender.name());
/// } else {
///     println!("当前平台不支持系统日志");
/// }
/// ```
pub fn get_syslog_appender(app_name: &str) -> Option<Box<dyn SyslogAppender>> {
    // 当启用 mock-syslog feature 时，返回 MockSyslogAppender (AC-8.6.4)
    #[cfg(feature = "mock-syslog")]
    {
        Some(Box::new(mock::MockSyslogAppender::new(app_name)))
    }

    #[cfg(all(not(feature = "mock-syslog"), target_os = "windows"))]
    {
        Some(Box::new(windows::WindowsEventLog::new(app_name)))
    }

    #[cfg(all(not(feature = "mock-syslog"), target_os = "linux"))]
    {
        Some(Box::new(linux::JournaldAppender::new(app_name)))
    }

    #[cfg(all(not(feature = "mock-syslog"), target_os = "macos"))]
    {
        Some(Box::new(macos::OsLogAppender::new(app_name)))
    }

    #[cfg(all(
        not(feature = "mock-syslog"),
        not(any(target_os = "windows", target_os = "linux", target_os = "macos"))
    ))]
    {
        let _ = app_name;
        None
    }
}

/// 写入 FATAL 日志到系统日志（带降级和限流）
///
/// 此函数在 FATAL 事件触发时由 `async_rt/worker` 调用。
/// 系统日志写入是同步的，确保进程崩溃前完成写入。
///
/// # Arguments
///
/// * `event` - 日志事件
/// * `app_name` - 应用名称，用于系统日志标识
///
/// # 行为
///
/// - 成功：日志写入系统日志
/// - 失败：降级到 stderr，使用限流机制输出警告
/// - 平台不支持：降级到 stderr，使用限流机制输出警告
///
/// # 限流机制
///
/// 降级警告每 1000 次输出一次，避免刷屏。
/// 原始日志内容始终输出到 stderr。
///
/// # 示例
///
/// ```rust,ignore
/// use log4r::appender::syslog::write_fatal_to_syslog;
/// use log4r::{LogEvent, Level};
///
/// let event = LogEvent::new(Level::Fatal, "my_app", "严重错误");
/// write_fatal_to_syslog(&event, "my_app");
/// ```
pub fn write_fatal_to_syslog(event: &LogEvent, app_name: &str) {
    // 内部降级处理函数
    let fallback_to_stderr = |reason: &str| {
        // 始终输出原始日志到 stderr (AC-8.5.2)
        eprintln!(
            "[FATAL] {} [{}] {}: {}",
            event.timestamp, event.level, event.target, event.message
        );

        // 限流输出警告信息 (AC-8.5.3, AC-8.5.4)
        if FALLBACK_RATE_LIMITER.should_log_warning() {
            eprintln!(
                "[log4r] Failed to write to system log: {}, falling back to stderr",
                reason
            );
        }
    };

    match get_syslog_appender(app_name) {
        Some(appender) => {
            if let Err(e) = appender.write_syslog(event) {
                // 降级：写入 stderr (AC-8.5.1)
                fallback_to_stderr(&e.to_string());
            }
        }
        None => {
            // 平台不支持：降级到 stderr
            fallback_to_stderr("System log not supported on this platform");
        }
    }
}

/// 获取系统日志降级次数
///
/// 返回自程序启动以来系统日志写入失败并降级到 stderr 的总次数。
/// 可用于监控和诊断。
///
/// # Returns
///
/// 降级总次数
///
/// # 示例
///
/// ```rust,ignore
/// use log4r::appender::syslog::get_fallback_count;
///
/// let count = get_fallback_count();
/// if count > 0 {
///     println!("系统日志降级次数: {}", count);
/// }
/// ```
pub fn get_fallback_count() -> u64 {
    FALLBACK_RATE_LIMITER.get_count()
}

/// 重置降级计数器（仅用于测试）
///
/// 将降级计数器重置为 0。此函数仅在测试环境中可用。
#[cfg(test)]
pub fn reset_fallback_count() {
    FALLBACK_RATE_LIMITER.reset();
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::level::Level;
    use serial_test::serial;

    // UT-8.1-001: 测试 SyslogAppender trait 是 Send + Sync
    #[test]
    fn test_syslog_appender_trait_is_send_sync() {
        // GIVEN: SyslogAppender trait
        // WHEN: 检查 trait bounds
        // THEN: 编译通过即验证成功
        fn assert_send_sync<T: Send + Sync + ?Sized>() {}
        assert_send_sync::<dyn SyslogAppender>();
    }

    // UT-8.1-002: 测试 get_syslog_appender 在当前平台返回正确结果
    #[test]
    fn test_get_syslog_appender_returns_correct_result() {
        // GIVEN: 应用名称
        let app_name = "test_app";

        // WHEN: 获取系统日志 Appender
        let appender = get_syslog_appender(app_name);

        // THEN: 根据 feature 和平台返回正确结果
        // 当启用 mock-syslog feature 时，返回 MockSyslogAppender (AC-8.6.4)
        #[cfg(feature = "mock-syslog")]
        {
            assert!(appender.is_some());
            assert_eq!(
                appender.as_ref().map(|a| a.name()),
                Some("MockSyslogAppender")
            );
        }

        #[cfg(all(not(feature = "mock-syslog"), target_os = "windows"))]
        {
            assert!(appender.is_some());
            assert_eq!(appender.as_ref().map(|a| a.name()), Some("WindowsEventLog"));
        }

        #[cfg(all(not(feature = "mock-syslog"), target_os = "linux"))]
        {
            assert!(appender.is_some());
            assert_eq!(
                appender.as_ref().map(|a| a.name()),
                Some("JournaldAppender")
            );
        }

        #[cfg(all(not(feature = "mock-syslog"), target_os = "macos"))]
        {
            assert!(appender.is_some());
            assert_eq!(appender.as_ref().map(|a| a.name()), Some("OsLogAppender"));
        }

        #[cfg(all(
            not(feature = "mock-syslog"),
            not(any(target_os = "windows", target_os = "linux", target_os = "macos"))
        ))]
        {
            // 其他平台返回 None
            assert!(appender.is_none());
        }
    }

    // UT-8.1-003: 测试 Box<dyn SyslogAppender> 是 Send + Sync
    #[test]
    fn test_boxed_syslog_appender_is_send_sync() {
        // GIVEN: Box<dyn SyslogAppender>
        // WHEN: 检查 Send + Sync
        // THEN: 编译通过即验证成功
        fn assert_send<T: Send>() {}
        fn assert_sync<T: Sync>() {}

        assert_send::<Box<dyn SyslogAppender>>();
        assert_sync::<Box<dyn SyslogAppender>>();
    }

    // UT-8.1-004: 测试消息格式化包含所有字段 (AC: 8.1.4)
    #[test]
    fn test_log_event_contains_all_fields() {
        // GIVEN: 一个 FATAL 级别的 LogEvent
        let event = LogEvent::new(Level::Fatal, "my_app::module", "严重错误消息");

        // THEN: 事件应包含所有必要字段
        assert_eq!(event.level, Level::Fatal);
        assert_eq!(event.target, "my_app::module");
        assert_eq!(event.message, "严重错误消息");
        assert!(event.timestamp.year() >= 2020);
        assert!(event.write_to_syslog);
    }

    // =========================================================================
    // Story 8.5: 降级策略测试
    // =========================================================================

    // UT-8.5-003: 测试限流机制第 1 次输出警告 (AC: 8.5.4)
    #[test]
    fn test_rate_limiter_first_call_returns_true() {
        // GIVEN: 新的限流器
        let limiter = FallbackRateLimiter::new(1000);

        // WHEN: 第一次调用
        let should_log = limiter.should_log_warning();

        // THEN: 应该返回 true（第 1 次输出警告）
        assert!(should_log, "第 1 次调用应返回 true");
    }

    // UT-8.5-004: 测试限流机制第 2-999 次不输出警告 (AC: 8.5.4)
    #[test]
    fn test_rate_limiter_subsequent_calls_return_false() {
        // GIVEN: 新的限流器，已调用一次
        let limiter = FallbackRateLimiter::new(1000);
        let _ = limiter.should_log_warning(); // 第 1 次

        // WHEN: 第 2-999 次调用
        for i in 2..=999 {
            let should_log = limiter.should_log_warning();
            // THEN: 应该返回 false
            assert!(!should_log, "第 {} 次调用应返回 false", i);
        }
    }

    // UT-8.5-005: 测试限流机制第 1001 次输出警告 (AC: 8.5.4)
    // 注：第 1 次 (count=0) 返回 true，第 1001 次 (count=1000) 返回 true
    #[test]
    fn test_rate_limiter_1001st_call_returns_true() {
        // GIVEN: 新的限流器
        let limiter = FallbackRateLimiter::new(1000);

        // WHEN: 调用 1000 次（第 1 次到第 1000 次）
        for _ in 0..1000 {
            let _ = limiter.should_log_warning();
        }
        // 第 1001 次调用
        let should_log_1001 = limiter.should_log_warning();

        // THEN: 第 1001 次应该返回 true（count=1000，1000 % 1000 == 0）
        assert!(should_log_1001, "第 1001 次调用应返回 true");
    }

    // UT-8.5-007: 测试 get_fallback_count() 返回正确计数 (AC: 8.5.4)
    #[test]
    fn test_rate_limiter_get_count() {
        // GIVEN: 新的限流器
        let limiter = FallbackRateLimiter::new(1000);

        // WHEN: 调用 5 次
        for _ in 0..5 {
            let _ = limiter.should_log_warning();
        }

        // THEN: 计数应为 5
        assert_eq!(limiter.get_count(), 5);
    }

    // UT-8.5-008: 测试 reset_fallback_count() 重置计数器 (AC: 8.5.4)
    #[test]
    fn test_rate_limiter_reset() {
        // GIVEN: 已调用多次的限流器
        let limiter = FallbackRateLimiter::new(1000);
        for _ in 0..100 {
            let _ = limiter.should_log_warning();
        }
        assert_eq!(limiter.get_count(), 100);

        // WHEN: 重置
        limiter.reset();

        // THEN: 计数应为 0
        assert_eq!(limiter.get_count(), 0);
    }

    // UT-8.5-001: 测试系统日志写入失败时不 panic (AC: 8.5.1)
    #[test]
    fn test_write_fatal_to_syslog_no_panic() {
        // GIVEN: 重置全局计数器
        reset_fallback_count();

        // GIVEN: 一个 FATAL 事件
        let event = LogEvent::new(Level::Fatal, "test_app", "测试 FATAL 消息");

        // WHEN: 调用 write_fatal_to_syslog
        // THEN: 不应该 panic（无论平台是否支持）
        write_fatal_to_syslog(&event, "test_app");

        // 验证函数正常返回（测试通过即验证）
    }

    // UT-8.5-006: 测试降级后正常 Appender 继续工作 (AC: 8.5.5)
    #[test]
    fn test_fallback_does_not_affect_other_operations() {
        // GIVEN: 重置全局计数器
        reset_fallback_count();

        // GIVEN: 多个 FATAL 事件
        let event1 = LogEvent::new(Level::Fatal, "test_app", "第一条 FATAL");
        let event2 = LogEvent::new(Level::Fatal, "test_app", "第二条 FATAL");

        // WHEN: 连续调用 write_fatal_to_syslog
        write_fatal_to_syslog(&event1, "test_app");
        write_fatal_to_syslog(&event2, "test_app");

        // THEN: 两次调用都应正常完成，不影响后续操作
        // 验证计数器正确递增（如果发生降级）
        let count = get_fallback_count();
        // 在支持的平台上可能为 0（成功写入），在不支持的平台上为 2
        assert!(
            count == 0 || count == 2,
            "计数器应为 0 或 2，实际为 {}",
            count
        );
    }

    // UT-8.5-009: 测试全局 get_fallback_count 函数
    #[test]
    fn test_global_get_fallback_count() {
        // GIVEN: 重置全局计数器
        reset_fallback_count();

        // WHEN: 获取初始计数
        let initial = get_fallback_count();

        // THEN: 初始计数应为 0
        assert_eq!(initial, 0, "重置后计数应为 0");
    }

    // =========================================================================
    // Story 8.6: Mock 系统日志测试
    // =========================================================================

    // UT-8.6-005: 测试 mock 模块在测试环境中可用 (AC: 8.6.1)
    #[test]
    fn test_mock_module_available_in_test() {
        // GIVEN: 测试环境
        // WHEN: 访问 mock 模块
        // THEN: 应该可以访问（编译通过即验证成功）
        use super::mock::MockSyslogAppender;
        let appender = MockSyslogAppender::new("test_app");
        assert_eq!(appender.name(), "MockSyslogAppender");
    }

    // UT-8.6-008: 测试 MockSyslogAppender 与 write_fatal_to_syslog 集成
    #[test]
    #[serial]
    fn test_mock_syslog_integration_with_write_fatal() {
        use super::mock::{clear_mock_syslog_events, get_mock_syslog_events, MockSyslogAppender};

        // GIVEN: 清空 Mock 日志
        clear_mock_syslog_events();

        // WHEN: 直接使用 MockSyslogAppender 写入
        let appender = MockSyslogAppender::new("integration_test");
        let event = LogEvent::new(Level::Fatal, "test_target", "集成测试消息");
        let result = appender.write_syslog(&event);

        // THEN: 写入成功，事件被捕获
        assert!(result.is_ok());
        let events = get_mock_syslog_events();
        assert_eq!(events.len(), 1);
        assert_eq!(events[0].message, "集成测试消息");
    }
}
